package made.util;

import game.core.G;
import game.core.Game;

public class GameStateAnalyzer
{
    protected static final int MAX_PATH_DISTANCE = 153;
    protected Game _previousGame;
    protected Game _currentGame;
    
    public GameStateAnalyzer()
    {
        _previousGame = null;
        _currentGame = null;
    }
    
    public void updateData(Game previousGame, Game currentGame)
    {
        _previousGame = previousGame;
        _currentGame = currentGame;
    }
    
    public GameEntity getNearestPillInc(Game game, int currentPacmanIndex)
    {// Gets the location of the nearest pill including power pills
        GameEntity nearestPill = new GameEntity();
        
        // get all active pills
        int[] activePills = game.getPillIndicesActive();

        // get all active power pills
        int[] activePowerPills = game.getPowerPillIndicesActive();

        // create a target array that includes all ACTIVE pills and power pills
        int[] targetsArray = new int[activePills.length + activePowerPills.length];

        for (int i = 0; i < activePills.length; i++)
            targetsArray[i] = activePills[i];

        for (int i = 0; i < activePowerPills.length; i++)
            targetsArray[activePills.length + i] = activePowerPills[i];

        // return the next direction once the closest target has been identified
        nearestPill.index = game.getTarget(currentPacmanIndex, targetsArray, true, G.DM.PATH);
        nearestPill.x = game.getX(nearestPill.index);
        nearestPill.y = game.getY(nearestPill.index);
        nearestPill.pathDistance = game.getPathDistance(currentPacmanIndex, nearestPill.index);
        nearestPill.euclidianDistance = game.getEuclideanDistance(currentPacmanIndex, nearestPill.index);
        
        return nearestPill;
    }
    
    public GameEntity getNearestPillExc(Game game, int currentPacmanIndex)
    {// Gets the location of the nearest pill excluding power pills
        GameEntity nearestPill = new GameEntity();
        
        // get all active pills
        int[] activePills = game.getPillIndicesActive();

        // create a target array that includes all ACTIVE pills and power pills
        int[] targetsArray = new int[activePills.length];

        for (int i = 0; i < activePills.length; i++)
            targetsArray[i] = activePills[i];

        // return the next direction once the closest target has been identified
        nearestPill.index = game.getTarget(currentPacmanIndex, targetsArray, true, G.DM.PATH);
        nearestPill.x = game.getX(nearestPill.index);
        nearestPill.y = game.getY(nearestPill.index);
        nearestPill.pathDistance = game.getPathDistance(currentPacmanIndex, nearestPill.index);
        nearestPill.euclidianDistance = game.getEuclideanDistance(currentPacmanIndex, nearestPill.index);
        
        return nearestPill;
    }
    
    public GhostEntity getNearestGhost(Game game, int currentPacmanIndex)
    {
        GhostEntity nearestGhost = new GhostEntity();
        int nextGhostIndex = -1;
        int nextGhostDistance = -1;

        for (int i = 0; i < Game.NUM_GHOSTS; i++)
        {
            if (game.getLairTime(i) == 0)
            {
                nextGhostIndex = game.getCurGhostLoc(i);
                nextGhostDistance = game.getPathDistance(currentPacmanIndex, nextGhostIndex);

                if (nextGhostDistance < nearestGhost.pathDistance)
                {
                    nearestGhost.id = i;
                    nearestGhost.index = nextGhostIndex;
                    nearestGhost.pathDistance = nextGhostDistance;
                }                
            }
        }
        
        if (nearestGhost.index >= 0)
        {
            nearestGhost.x = game.getX(nearestGhost.index);
            nearestGhost.y = game.getY(nearestGhost.index);
            
            if (game.getEdibleTime(nearestGhost.id) > 0)
                nearestGhost.pathDistance /= 2; // Ghost move twice as slow when pacman has eaten power pills
            
            nearestGhost.euclidianDistance = game.getEuclideanDistance(currentPacmanIndex, nearestGhost.index);                    
        }

        return nearestGhost;
    }
    
    public int getMaxDistance(Game game)
    {
        return game.getPathDistance(0, 1291);
    }
    
    public float getNormalizedPathDistance(int pathDistance)
    {
        if (pathDistance >= 0)
            return pathDistance / (float)MAX_PATH_DISTANCE;
        else
            return 0.0f;
    }
    
    public float getNormalizedEdibleTime(float edibleTime)
    {
        if (edibleTime >= 0)
            return edibleTime / (float)Game.EDIBLE_TIME;
        else
            return 0.0f;
    }
    
    public int getBestAvailable()
    {
        return 0;
    }
    
    public float getAverageGhostDistance(Game game, int currentPacmanIndex)
    {
        float averageGhostDistance = 0.0f;

        for (int i = 0; i < Game.NUM_GHOSTS; i++)
        {
            averageGhostDistance += (float) game.getPathDistance(currentPacmanIndex, game.getCurGhostLoc(i));
        }

        return averageGhostDistance / 4.0f;
    }
    
    public boolean ghostDied()
    {
        boolean death = false;
        
        if (!pacManDied() && !levelIncreased())
        {
            for (int i = 0; i < Game.NUM_GHOSTS; i++)
            {
                boolean ghostAlivePrevious = !(_previousGame.getLairTime(i) > 0); 
                boolean ghostAliveNext = !(_previousGame.getLairTime(i) > 0);
                
                if (ghostAlivePrevious && !ghostAliveNext)
                {
                    death = true;
                    break;
                }
            }
        }
        
        return death;
    }
    
    public boolean pacManDied()
    {
//        boolean death = false;        
//        int currentPacmanPosition = currentGame.getCurPacManLoc();
//        
//        if (currentPacmanPosition == currentGame.getInitialPacPosition())
//        {
//            int[] initialPositionNeigbours = getinitialPositionNeighbours(previousGame);
//            int previousPacManPosition = previousGame.getCurPacManLoc();
//            
//            for (int i = 0; i < 4; i++)
//            {  
//                if (previousPacManPosition == initialPositionNeigbours[i]);
//                    death = false;
//            }            
//        }

        boolean death = (_currentGame.getLivesRemaining() - _previousGame.getLivesRemaining()) < 0;
        
        return death;
    }
    
    public boolean levelIncreased()
    {
        boolean increased = (_currentGame.getCurLevel() - _previousGame.getCurLevel()) > 0;
        
        return increased;
    }
    
    public boolean pacManAtePill()
    {
        boolean atePill = false;
        
        int[] activePillsPrevious = _previousGame.getPillIndicesActive();
        int[] activePillsCurrent = _currentGame.getPillIndicesActive();
        
        if ((activePillsCurrent.length - activePillsPrevious.length) < 0) 
            atePill = true;        
        
        return atePill;
    }
    
    public boolean pacManAtePowerPill()
    {
        boolean atePill = false;
        
        int[] activePowerPillsPrevious = _previousGame.getPowerPillIndicesActive();
        int[] activePowerPillsCurrent = _currentGame.getPowerPillIndicesActive();
        
        if ((activePowerPillsCurrent.length - activePowerPillsPrevious.length) < 0) 
            atePill = true;        
        
        return atePill;
    }
    
    public boolean pacManAteGhost()
    {        
        boolean ateGhost = false;
        
        if (!(pacManDied() || levelIncreased()))
        {
            for (int i = 0; i < Game.NUM_GHOSTS; i++)
            {
                int ghostLairTimePrevious = _previousGame.getLairTime(i);
                int ghostLairTimeCurrent = _currentGame.getLairTime(i);
                
                if (ghostLairTimePrevious == 0 && ghostLairTimeCurrent > 0)
                {
                    ateGhost = true;
                }                    
            }            
        }        
        
        return ateGhost;
    }
    
    public int[] getinitialPositionNeighbours(Game game)
    {
        int[] initialPositionNeighbors = new int[4];
        
        for (int i = 0; i < 4; i++)
        {            
            initialPositionNeighbors[i] = game.getNeighbour(game.getInitialPacPosition(), i);
        }
        
        return initialPositionNeighbors;
    }
    
    public class GameEntity
    {
        public int index;
        public int x;
        public int y;
        public int pathDistance;
        public double euclidianDistance;
        
        public GameEntity()
        {
            index = -1;
            pathDistance = Integer.MAX_VALUE;
            euclidianDistance = Double.MAX_VALUE;
            x = -1;
            y = -1;
        }
    };

    public class GhostEntity extends GameEntity
    {
        public int id;
        
        public GhostEntity()
        {
            super();
            id = -1;            
        }
    };
}
